﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public enum RolyType
{
    Normal,
    Start,
    End,
    Obsticle
}


public class AstarUtility : MonoBehaviour {

    public static AstarUtility Instance { get; private set; }

    [HideInInspector]
    public Color[] colors;

    public Vector2 startPoint; //起点网格坐标
    public Vector2 endPoint;    //终点网格坐标
    public CubeGrid[,] cubeGrids;   //网格

    private List<CubeGrid> openList;    //开启列表
    private List<CubeGrid> closeList;   //关闭列表

    private Stack<CubeGrid> path;   //路径栈

    private void Awake()
    {
        Instance = this;
        colors = new Color[] {Color.green,Color.red,Color.blue,Color.yellow};
        openList = new List<CubeGrid>();
        closeList = new List<CubeGrid>();
        path = new Stack<CubeGrid>();
    }

    //Use this for initialization
    IEnumerator Start()
    {
        yield return new WaitForSeconds(0.1f);
        AStartFindPath();
    }

    //private void Update()
    //{
    //    if (Input.GetKeyDown(KeyCode.Space))
    //    {
    //        AStartFindPath();
    //    }
    //}

    void AStartFindPath()
    {
        openList.Add(cubeGrids[(int)startPoint.x, (int)startPoint.y]);
        //F值最佳的格子，开始时是起点
        CubeGrid bestGrid = openList[0];
        //开启列表中有格子，并且当前格子不是终点
        while (openList.Count > 0 && bestGrid.gridType != RolyType.End)
        {
            //获取排序后F值最小的格子
            bestGrid = openList[0];

            //循环跳出条件 找到了终点
            if (bestGrid.gridType == RolyType.End)
            {
                Debug.Log("找到了路径");
                GeneratePath(bestGrid);
                return;
            }

            //遍历上下左右 斜上下左右 8个格子
            for (int i = -1; i <= 1; i++)
            {
                for (int j = -1; j <= 1; j++)
                {
                    //移除中心格子的坐标
                    if (i == 0 && j == 0) continue;

                    int newX = bestGrid.x + i;
                    int newY = bestGrid.y + j;

                    if (newX < 0 
                        //数组越界
                        || newY < 0 
                        || newX >= cubeGrids.GetLength(0) 
                        || newY >= cubeGrids.GetLength(1) 
                        //这个格子是障碍物
                        || cubeGrids[newX, newY].gridType == RolyType.Obsticle 
                        //这个格子被计算过了
                        || closeList.Contains(cubeGrids[newX, newY]))
                        continue;

                    //计算当前格子的FGH
                    //计算当前格子的G
                    int g = bestGrid.G + CountG(i, j);
                    //如果是第一次计算或者新计算的比原来的小
                    if (cubeGrids[newX, newY].G == 0 || cubeGrids[newX, newY].G > g)
                    {
                        //更新G值
                        cubeGrids[newX, newY].G = g;
                        //更新父格子
                        cubeGrids[newX, newY].parent = bestGrid;
                    }

                    //计算当前格子的H值
                    cubeGrids[newX,newY].H = CountH(newX, newY);
                    //计算当前格子的F值
                    cubeGrids[newX, newY].F = cubeGrids[newX, newY].G + cubeGrids[newX, newY].H;

                    //判断当前格子是否在OpenList中
                    if (!openList.Contains(cubeGrids[newX, newY]))
                    {
                        openList.Add(cubeGrids[newX, newY]);
                    }
                }
            }

            //在Openlist中移除当前中心格子
            openList.Remove(bestGrid);
            //添加到Closelist中
            closeList.Add(bestGrid);
            
            //判断openlist是否空了
            if (openList.Count == 0)
            {
                Debug.Log("找不到路径");
            }

            openList.Sort();
        }
    }

    /// <summary>
    /// 生成路径
    /// </summary>
    /// <param name="cubeGrid"></param>
    void GeneratePath(CubeGrid cubeGrid)
    {
        if (cubeGrid.parent == null)
        {
            ShowPath();
        }
        else
        {
            path.Push(cubeGrid.parent);
            GeneratePath(cubeGrid.parent);
        }
    }

    /// <summary>
    /// 显示路径
    /// </summary>
    void ShowPath()
    {
        while (path.Count > 0)
        {
            path.Pop().Show();
        }
    }

    /// <summary>
    /// 计算G值，对角线时为14，直线时为10
    /// </summary>
    /// <param name="i"></param>
    /// <param name="j"></param>
    /// <returns></returns>
    int CountG(int i, int j)
    {
        return i != 0 && j != 0 ? 14 : 10;
    }

    /// <summary>
    /// 计算H值
    /// </summary>
    /// <param name="crtX"></param>
    /// <param name="crtY"></param>
    /// <returns></returns>
    int CountH(int crtX, int crtY)
    {
        return (Mathf.Abs(crtX - (int)endPoint.x) + Mathf.Abs(crtY - (int)endPoint.y)) * 10;
    }
}
